﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Li.DingTalk
{

    public class AccessTokenBag
    {
        public string CorpId { get; set; }
        public string CorpSecret { get; set; }
        /// <summary>  
        /// 票据的值  
        /// </summary>  
        public String Value { get; set; }

        /// <summary>  
        /// 票据的开始时间  
        /// </summary>  
        public DateTime Begin { get; set; } = DateTime.Parse("1970-01-01");
    }

    public class jsListBag
    {
        /// <summary>  
        /// 票据的值  
        /// </summary>  
        public String Value { get; set; }

        /// <summary>  
        /// 票据的开始时间  
        /// </summary>  
        public DateTime Begin { get; set; } = DateTime.Parse("1970-01-01");
    }


    /// <summary>  
    /// 访问票据  
    /// </summary>  
    public class AccessTokenContainer
    {
        //AccessToken
        static Dictionary<string, AccessTokenBag> AccessTokenCollection = new Dictionary<string, AccessTokenBag>(StringComparer.OrdinalIgnoreCase);

        //jsListBag
        static Dictionary<string, jsListBag> jsList = new Dictionary<string, jsListBag>();


        #region  AccessToken

        /// <summary>
        /// 注册应用凭证信息，此操作只是注册，不会马上获取Token，并将清空之前的Token，
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="corpSecret"></param>
        public static void Register(string corpId, string corpSecret)
        {
            AccessTokenCollection[corpId] = new AccessTokenBag()
            {
                CorpId = corpId,
                CorpSecret = corpSecret,
                Value = "", //token
                Begin = DateTime.MinValue
            };
        }

        /// <summary>
        /// 使用完整的应用凭证获取Token，如果不存在将自动注册
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="getNewToken"></param>
        /// <returns></returns>
        public static string TryGetToken(string corpId, bool getNewToken = false)
        {
            if (!CheckRegistered(corpId) || getNewToken)
            {
                GetTokenResult(corpId, true);
            }
            return GetToken(corpId);
        }
        /// <summary>
        /// 检查是否已经注册
        /// </summary>
        /// <param name="corpId"></param>
        /// <returns></returns>
        public static bool CheckRegistered(string corpId)
        {
            return AccessTokenCollection.ContainsKey(corpId);
        }

        /// <summary>
        /// 获取可用Token
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="getNewToken">是否强制重新获取新的Token</param>
        /// <returns></returns>
        public static string GetToken(string corpId, bool getNewToken = false)
        {
            return GetTokenResult(corpId, getNewToken);
        }

        /// <summary>
        /// 获取可用Token
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="getNewToken">是否强制重新获取新的Token</param>
        /// <returns></returns>
        public static string GetTokenResult(string corpId, bool getNewToken = false)
        {
            if (!AccessTokenCollection.ContainsKey(corpId))
            {
                //corpId = "ding4d58972322cf686735c2f4657eb6378f";
                throw new Exception("此CorpId尚未注册，请先使用AccessTokenContainer.Register完成注册（全局执行一次即可）！");
            }

            var accessTokenBag = AccessTokenCollection[corpId];
            //ConstVars.CACHE_TIME是缓存时间(常量，也可放到配置文件中)，这样在有效期内则直接从缓存中获取票据，不需要再向服务器中获取。  
            if (!getNewToken && accessTokenBag.Begin.AddSeconds(ConstVars.CACHE_TIME) >= DateTime.Now)
            {//没有强制更新，并且没有超过缓存时间  
                return accessTokenBag.Value;
            }

            string TokenUrl = Urls.gettoken;
            string apiurl = $"{TokenUrl}?{Keys.corpid}={corpId}&{Keys.corpsecret}={accessTokenBag.CorpSecret}";
            string resultJson = RequestHelper.Get(@apiurl);

            TokenResult tokenResult = JsonConvert.DeserializeObject<TokenResult>(resultJson);
            if (tokenResult.ErrCode == ErrCodeEnum.OK)
            {
                accessTokenBag.Value = tokenResult.Access_token;
                accessTokenBag.Begin = DateTime.Now;
            }
            else
            {
                return string.Empty;//没有获取成功时
            }
            return accessTokenBag.Value;
        }

        #endregion

        #region jsapi_ticket
        /// <summary>
        /// 使用完整的应用凭证获取Token，如果不存在将自动注册
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="accessToken"></param>
        /// <param name="getNewToken"></param>
        /// <returns></returns>
        public static string TryGetJsTicket(string corpId,string accessToken, bool getNewToken = false)
        {
            if (jsList.ContainsKey(corpId))
            {
                var jstoken = jsList[corpId];
                if (jstoken.Begin.AddSeconds(6000) > DateTime.Now) //有效区内
                {
                    return jstoken.Value;
                }
            }
            //重获取
            string apiurl = $"{"https://oapi.dingtalk.com/get_jsapi_ticket"}?{Keys.access_token}={ accessToken}";
            string resultJson = RequestHelper.Get(@apiurl);
            jsapi_ticketResult ticketResult = JsonConvert.DeserializeObject<jsapi_ticketResult>(resultJson);
            if (ticketResult.ErrCode == ErrCodeEnum.OK)
            {
                if (!jsList.ContainsKey(corpId))
                {
                    jsList.Add(corpId, new jsListBag() { Value = ticketResult.ticket, Begin = DateTime.Now });
                }
                else {
                    jsList[corpId].Value = ticketResult.ticket;
                    jsList[corpId].Begin = DateTime.Now;
                }
                return ticketResult.ticket;
            }

            throw new Exception("没有获取到有效的jsapi_ticket,请重获取！");
        }
        #endregion



    }
    /// <summary>  
        /// 访问票据  
        /// </summary>  
    public  class SSOAccessTokenContainer
    {
        static Dictionary<string, AccessTokenBag> AccessTokenCollection =
          new Dictionary<string, AccessTokenBag>(StringComparer.OrdinalIgnoreCase);


        /// <summary>
        /// 注册应用凭证信息，此操作只是注册，不会马上获取Token，并将清空之前的Token，
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="corpSecret"></param>
        public static void Register(string corpId, string SSOSecret)
        {
            AccessTokenCollection[corpId] = new AccessTokenBag()
            {
                CorpId = corpId,
                CorpSecret = SSOSecret,
                Value = "", //token
                Begin = DateTime.MinValue
            };
        }

        /// <summary>
        /// 使用完整的应用凭证获取Token，如果不存在将自动注册
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="getNewToken"></param>
        /// <returns></returns>
        public static string TryGetToken(string corpId, bool getNewToken = false)
        {
            if (!CheckRegistered(corpId) || getNewToken)
            {
                GetTokenResult(corpId,true);
            }
            return GetToken(corpId);
        }
        /// <summary>
        /// 检查是否已经注册
        /// </summary>
        /// <param name="corpId"></param>
        /// <returns></returns>
        public static bool CheckRegistered(string corpId)
        {
            return AccessTokenCollection.ContainsKey(corpId);
        }

        /// <summary>
        /// 获取可用Token
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="getNewToken">是否强制重新获取新的Token</param>
        /// <returns></returns>
        public static string GetToken(string corpId, bool getNewToken = false)
        {
            return GetTokenResult(corpId, getNewToken);
        }

        /// <summary>
        /// 获取可用Token
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="getNewToken">是否强制重新获取新的Token</param>
        /// <returns></returns>
        public static string GetTokenResult(string corpId, bool getNewToken = false)
        {
            if (!AccessTokenCollection.ContainsKey(corpId))
            {
                throw new Exception("此CorpId尚未注册，请先使用AccessTokenContainer.Register完成注册（全局执行一次即可）！");
            }

            var accessTokenBag = AccessTokenCollection[corpId];
            //ConstVars.CACHE_TIME是缓存时间(常量，也可放到配置文件中)，这样在有效期内则直接从缓存中获取票据，不需要再向服务器中获取。  
            if (!getNewToken && accessTokenBag.Begin.AddSeconds(ConstVars.CACHE_TIME) >= DateTime.Now)
            {//没有强制更新，并且没有超过缓存时间  
               return accessTokenBag.Value;
            }

            string TokenUrl = Urls.sso_gettoken;
            string apiurl = $"{TokenUrl}?{Keys.corpid}={corpId}&{Keys.corpsecret}={accessTokenBag.CorpSecret}";
            string resultJson = RequestHelper.Get(@apiurl);

            TokenResult tokenResult = JsonConvert.DeserializeObject<TokenResult>(resultJson);
            if (tokenResult.ErrCode == ErrCodeEnum.OK)
            {
                accessTokenBag.Value = tokenResult.Access_token;
                accessTokenBag.Begin = DateTime.Now;
            }
            else {
                return string.Empty;//没有获取成功时
            }
            return accessTokenBag.Value;
        }
      
    }



}
